package cn.ichiva.tushare.sdk.tushare;

import cn.ichiva.common.DataHelper;
import cn.ichiva.common.kv.impl.KVDBImpl;
import cn.ichiva.tushare.sdk.tushare.entity.TuTable;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 可缓存的数据
 *
 * 使用leveDb进行本地缓存
 */
@Slf4j
public abstract class TuDataCacheAble extends AbstractTuData implements Cloneable{
    /**
     * 服务器访问次数
     */
    private AtomicInteger nVisits = new AtomicInteger(0);
    /**
     * 620积分目标限制60次/分钟
     */
    public static int limit = 59;
    private static long time = System.currentTimeMillis();


    private KVDBImpl cache;

    private void initDB(File cacheFile) {
        if(log.isTraceEnabled()){
            log.trace("初始化 Level DB path = {}",cacheFile.getAbsoluteFile());
        }
        this.cache = new KVDBImpl(cacheFile);
    }

    public TuDataCacheAble(TuConfig config) {
        super(config);
        if(config instanceof TuCacheConfig){
            File cacheFile = ((TuCacheConfig) config).getCacheFile();
            initDB(cacheFile);
        }
    }

    /**
     * 获取缓存key
     * @return
     */
    public String getCacheKey(){
        String start = getRequest().getParams().get("start_date");
        String end = getRequest().getParams().get("end_date");
        byte[] bytes = DataHelper.toByte(getRequest());
        return String.format("%s/%s-%s-%s",this.getClass().getSimpleName(),start,end,DataHelper.md5String(bytes));
    }

    /**
     * 取缓存数据
     * @return
     */
    @Override
    public Optional<TuTable> get() {
        if(cache == null){
            return get0();
        }else {
            String cacheKey = getCacheKey();
            byte[] bytes = cache.get(cacheKey);
            if(bytes != null){
                if (log.isTraceEnabled()) {
                    log.trace("命中缓存 key = {}", getRequest().getApi());
                }
                return Optional.of((TuTable) DataHelper.toObject(bytes));
            }

            Optional<TuTable> res = get0();
            res.ifPresent(e -> cache.put(cacheKey, DataHelper.toByte(e)));
            return res;
        }
    }

    public Optional<TuTable> get0() {
        Optional<TuTable> tuTable = super.get();
        if(nVisits.get() >= limit) checkLimit();
        nVisits.incrementAndGet();
        return tuTable;
    }


    /**
     * 全局服务器访问限流
     */
    public synchronized void checkLimit(){
        if(nVisits.get() >= limit){
            long t1 = System.currentTimeMillis() - time;
            if(t1 < 60 * 1000){
                try {
                    long t2 = 60 * 1000 - t1;
                    if (log.isDebugEnabled()) {
                        log.debug("服务器访问过快,休息 {}s",t2 / 1000);
                    }
                    Thread.sleep(t2);
                } catch (InterruptedException e) {}
            }

            time = System.currentTimeMillis();
            nVisits.set(0);
        }
    }
}
